import SparkMD5 from 'spark-md5';

class MerkleNode {
  constructor(h, l = null, r = null) {
    this.h = h;
    this.l = l;
    this.r = r;
  }
}

class MerkleTree333 {
  constructor(nodes) {
    if (nodes.length === 0) {
      throw new Error('Empty Nodes');
    }

    if (typeof nodes[0] ==='string') {
      this.leafs = nodes.map((node) => new MerkleNode(node));
    } else {
      this.leafs = nodes;
    }

    this.root = this.buildTree();
  }

  getRootHash() {
    return this.root.h;
  }

  buildTree() {
    // 实现构建 Merkle 树的逻辑。根据叶子节点创建父节点，一直到根节点。
    let currentLevelNodes = this.leafs;
    while (currentLevelNodes.length > 1) {
      const parentNodes = [];
      for (let i = 0; i < currentLevelNodes.length; i += 2) {
        const left = currentLevelNodes[i];
        const right = i + 1 < currentLevelNodes.length? currentLevelNodes[i + 1] : null;
        // 具体的哈希计算方法
        const parentHash = this.calculateHash(left, right);
        parentNodes.push(new MerkleNode(parentHash, left, right));
      }
      currentLevelNodes = parentNodes;
    }

    return currentLevelNodes[0]; // 返回根节点
  }

  // 序列化 Merkle 树
  serialize() {
    const serializeNode = (node) => {
      if (node === null) {
        return null;
      }
      return {
        h: node.h,
        l: serializeNode(node.l),
        r: serializeNode(node.r)
      };
    };

    const serializedRoot = serializeNode(this.root);
    return JSON.stringify(serializedRoot);
  }

  // 反序列化 Merkle 树
  static deserialize(serializedTree) {
    const parsedData = JSON.parse(serializedTree);

    const deserializeNode = (data) => {
      if (data === null) {
        return null;
      }
      return new MerkleNode(data.h, deserializeNode(data.l), deserializeNode(data.r));
    };

    const root = deserializeNode(parsedData);
    if (!root) {
      throw new Error('Invalid serialized tree data');
    }

    // 创建一个包含所有叶子节点的数组，这是为了与 MerkleTree 的构造函数兼容
    // 没有保存这些叶子节点的序列化版本，所以这里需要一些额外的逻辑来处理
    // 如果你需要将整个树的所有节点存储为序列化版本，那么可能需要修改这部分逻辑
    const extractLeafNodes = (node) => {
      if (node.l === null && node.r === null) {
        return [node];
      }
      return [
        ...(node.l? extractLeafNodes(node.l) : []),
        ...(node.r? extractLeafNodes(node.r) : [])
      ];
    };
    const leafNodes = extractLeafNodes(root);

    return new MerkleTree333(leafNodes);
  }

  // 这里是 calculateHash 方法的定义
  private calculateHash(left, right) {
    return right? SparkMD5.hash(left.h + right.h) : left.h;
  }
}